﻿using FrameWork.Log;
using MyServer.Common.Tools;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FrameWork.Setting;
using System.ComponentModel;

namespace MyServer.Common
{

    /// <summary>
    /// 表示操作的结果
    /// </summary>
    public enum OperateResult
    {
        /// <summary>
        /// 操作成功执行
        /// </summary>
        Success,
        /// <summary>
        /// 操作被忽略
        /// </summary>
        Ignore,
        /// <summary>
        /// 操作失败
        /// </summary>
        Fail
    }
    /// <summary>
    /// 表示通过队列处理数据的项的基类
    /// </summary>
    [SettingParentDefine]
    public abstract class QueueOperateItemBase : LogableClassBase
    {

        #region========私有变量========

        private object lockObj = new object();
        private object OpLockFullObj = new object();
        private bool IsStop = true;

        #endregion

        #region==========属性==========

        /// <summary>
        /// 表示该对象的操作工作实例
        /// </summary>
        public Task OperateMainTask { get; private set; }

        /// <summary>
        /// 表示该对象的操作队列
        /// </summary>
        protected DataPackageQueue OperateQueue { get; set; }

        /// <summary>
        /// 获取或设置数据处理器等待队列的速率
        /// </summary>
        [SettingItemDefine(SettingValueType.Int32, 10)]
        [DisplayName("监听频率")]
        [DefaultValue(10)]
        [Browsable(true)]
        [Description("表示该数据处理器工作线程当队列为空时休眠的时间间隔")]
        public int ListenRate { get; set; }

        #endregion

        #region========公有委托========

        /// <summary>
        /// 将要接收数据包的事件委托
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void BeforeOperateEventHandler(object sender, DataBeforeOperateEventArgs e);
        /// <summary>
        /// 接收数据包操作完成的事件委托
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void OperateCompeleteEventHandler(object sender, DataAfterOperateEventArgs e);
        /// <summary>
        /// 发生错误时的事件委托
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void ErrorCatchedEventHandler(object sender, ErrorCatchedEventArgs e);
        #endregion

        #region==========事件==========

        /// <summary>
        /// 数据读取之前
        /// </summary>
        public event BeforeOperateEventHandler BeforeOperateData;

        /// <summary>
        /// 数据读取之后
        /// </summary>
        public event OperateCompeleteEventHandler AfterOperateData;

        /// <summary>
        /// 发生错误时
        /// </summary>
        public event ErrorCatchedEventHandler ErrorCatched;

        #endregion

        #region========抽象函数========

        /// <summary>
        /// 执行一步操作
        /// </summary>
        protected abstract OperateResult DoOperateSetp(DataPackageCollection pkg, out DataPackageCollection Repkg);
        protected abstract bool BeforeOperateSetp(DataPackageCollection pkg);
        protected abstract bool AfterOperateSetp(DataPackageCollection pkg);

        #endregion

        #region========私有函数========

        protected void DoOperate()
        {
            lock (OpLockFullObj)
            {
                PrintLog(LogType.Info, "主操作线程启动！");
                int OperateSuccessCount = 0;                        //一次遍历队列队列操作成功数
                int OperateCount = 0;                               //一次遍历遍历的项目数
                while (IsStop == false)
                {
                    DataPackageCollection pkg;
                    if (OperateQueue.Count == 0)
                    {
                        System.Threading.Thread.Sleep(ListenRate);
                        continue;
                    }
                    if (OperateCount>=OperateQueue.Count)
                    {
                        if(OperateSuccessCount==0)
                        {
                            System.Threading.Thread.Sleep(ListenRate);
                            OperateCount = 0;
                            OperateSuccessCount = 0;
                            continue;
                        }
                    }
                    lock (OperateQueue)
                    {
                        if (!OperateQueue.TryDequeue(out pkg))
                            continue;
                    }
                    lock (lockObj)
                    {
                        DataBeforeOperateEventArgs e = new DataBeforeOperateEventArgs(pkg);
                        DataAfterOperateEventArgs e1 = new DataAfterOperateEventArgs(pkg, null);
                        if (pkg.PrecedenceLeft - 1 <= 0 || pkg.PrecedenceLeft > pkg.Precedence)//判定优先级
                        {
                            if (BeforeOperateData != null)
                                BeforeOperateData(this, e);
                            if (!e.Canceled)
                            {
                                OperateResult OpResult = OperateResult.Ignore;
                                try
                                {
                                    if (!BeforeOperateSetp(
                                        pkg))
                                    {
                                        continue;
                                    }
                                    DataPackageCollection repkg;
                                    OpResult = DoOperateSetp(pkg, out repkg);
                                    e1.ResultData = repkg;
                                }
                                catch (Exception ex)
                                {
#if DEBUG
                                throw;
#else
                                    ErrorCatchedEventArgs e2 = new ErrorCatchedEventArgs(ex, pkg);
                                    e2.Operate = ErrorOperate.RemoveCol;
                                    PrintLog(LogType.Waring, "操作时发生错误！正在处理...", ex);
                                    if (ErrorCatched != null)
                                    {
                                        ErrorCatched(this, e2);
                                    }
                                    switch (e2.Operate)
                                    {
                                        case ErrorOperate.RemoveCol:
                                            PrintLog(LogType.Waring, "正在移除出错的发送项...", pkg);
                                            continue;
                                        case ErrorOperate.StopSend:
                                            PrintLog(LogType.Error, "严重错误！正在停止发送线程...", pkg);
                                            goto EndOP;
                                        case ErrorOperate.Pass:
                                            PrintLog(LogType.Waring, "一般性错误，已忽略", pkg);
                                            break;
                                        case ErrorOperate.ClearQueue:
                                            PrintLog(LogType.Waring, "发送出错，正在清空发送队列...", pkg);
                                            lock (OperateQueue)
                                            {
                                                OperateQueue.Clear();
                                            }
                                            break;
                                    }
                                    OpResult = OperateResult.Fail;
#endif
                                }
                                e1.Result = OpResult;
                            }
                            else
                            {
                                e1.Result = OperateResult.Fail;
                            }
                            e1.Canceled = e.Canceled;
                            pkg.PrecedenceLeft = pkg.Precedence;
                            OperateSuccessCount += ((e1.Result == OperateResult.Success) ? 1 : 0);
                            if (!e.Canceled && e1.Result != OperateResult.Fail)
                            {
                                if (AfterOperateSetp(pkg))
                                {
                                    lock (OperateQueue)
                                    {
                                        OperateCount++;
                                        OperateQueue.Enqueue(pkg);
                                    }
                                }
                            }
                            if (AfterOperateData != null)
                                AfterOperateData(this, e1);

                        }
                        else
                        {
                            pkg.PrecedenceLeft--;
                        }

                    }
                }
            EndOP:
                PrintLog(LogType.Info, "主操作线程终止！");
            }
        }

        #endregion

        #region========公有函数========
        /// <summary>
        /// 开始监听接收队列
        /// </summary>
        public virtual void Start()
        {
            PrintLog(LogType.Info, "正在启动...");
            IsStop = false;
            if (OperateMainTask == null || OperateMainTask.Status != TaskStatus.Running)
            {
                PrintLog(LogType.Info, "正在构建工作线程...");
                OperateMainTask = new Task(DoOperate);
                PrintLog(LogType.Info, "正在启动工作线程...");
                OperateMainTask.Start();
            }
            else
            {
                PrintLog(LogType.Waring, "工作线程尚未结束，已跳过线程构造。");
            }
            PrintLog(LogType.Info, "启动完毕！");
        }

        /// <summary>
        /// 停止数据读取器
        /// </summary>
        public virtual void Stop()
        {
            PrintLog(LogType.Info, "正在停止...");
            this.IsStop = true;
            PrintLog(LogType.Info, "正在等待工作线程停止...");
            while (OperateMainTask.Status == TaskStatus.Running)
            {
                System.Threading.Thread.Sleep(10);
            }
            PrintLog(LogType.Info, "停止成功！");
        }

        /// <summary>
        /// 将指定数据列表项加入队列末尾
        /// </summary>
        public virtual void AddToQueue(DataPackageCollection pkg)
        {
            OperateQueue.Enqueue(pkg);
        }

        /// <summary>
        /// 获取队列长度
        /// </summary>
        /// <returns></returns>
        public virtual int GetQueueCount()
        {
            return OperateQueue.Count;
        }

        /// <summary>
        /// 清空队列
        /// </summary>
        public virtual void ClearQueue()
        {
            lock (lockObj)
            {
                OperateQueue.Clear();
            }
        }

        #endregion

        #region========构造函数========
        public QueueOperateItemBase()
        {
            this.OperateQueue = new DataPackageQueue();
            this.ListenRate = 10;
        }
        #endregion

    }
}
